/**
**************************************************************************************
*Founder Effect                                                                      *
*Copyright (C) 2006-2007, 5d Studios (www.5d-Studios.com)                            *
*                                                                                    *
*This library is free software; you can redistribute it and/or                       *
*modify it under the terms of the GNU Lesser General Public                          *
*License as published by the Free Software Foundation; either                        *
*version 2.1 of the License, or (at your option) any later version.                  *
*                                                                                    *
*This library is distributed in the hope that it will be useful,                     *
*but WITHOUT ANY WARRANTY; without even the implied warranty of                      *
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                   *
*Lesser General Public License for more details.                                     *
*                                                                                    *
*You should have received a copy of the GNU Lesser General Public                    *
*License along with this library; if not, write to the Free Software                 *
*Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA      *
**************************************************************************************
*/
#include "StdAfx.h"
#include "Emitter.h"
#include <math.h>
#include "../kernel.h"

extern Kernel* g_kernel;

#define TIME g_kernel->GetTime()

const float PI = 3.14159265358979323846f;
#define random()	((rand () & 0x7fff) / ((float)0x7fff))
#define crandom()	(2.0 * (random() - 0.5))

/**Helper function */
float NextRand()
{
    // give a random number::TODO Find a better rand function
    // this one sucks
    return (1.0f / (rand()/1000.0f))*2.0f;
}


unsigned int Emitter::m_emitterIDs = 0;

Emitter::Emitter(void)
{
    Reset();
    m_id = (++m_emitterIDs);
}

Emitter::~Emitter(void)
{
}

/** Update the Emitters */
void Emitter::Update(long dt)
{
    ClearDead();
    float deltaTime = g_kernel->GetFrameTime()/ 1000.0f;
    type_Particles::iterator it = m_particles.begin();
    for(; it!=m_particles.end(); it++)
    {
        Particle &p = *it;

        // kill the particle
        if ( TIME > p.lifeTime )
        {
            p.isDead = true;
            continue;
        }
        // CalculateJitter( p, p.velocity );
        Vector2f pos = (p.acceleration * p.velocity) * Friction * deltaTime;
        p.position = p.position + pos;
        // decreate the alpha value
        if ( TIME > p.nextAlphaUpdate )
        {
            p.alpha -= 0.01f; 
            p.nextAlphaUpdate = TIME + p.fadeTime;
        }

        Vector3f color = EndColor - p.color;
        Vector3f fade  = color * ColorFadeTime;
        p.color = p.color + fade;
        
    }

    if ( (m_particles.size() < MaxParticles) && TIME > m_spawnTimer && MaxTotalParticles >= m_particlesCreated )
    {
        Spawn();
        m_spawnTimer = TIME + SpawnRate;

    }

    //if ( TIME > LifeSpanOfEmitter )
    //{
    //    IEvent evt(EVT_RM_PARTICLE, TIME, new ParticleData(this), LT_PARTICLEMNG );
    //    EventManager::GetInstance()->TriggerEvent( evt );
    //}
}

/** Render the Emitters */
void Emitter::Render(IRender* r, ICamera* cam )
{
    type_Particles::iterator it = m_particles.begin();
    for(; it!=m_particles.end(); it++)
    {
        r->SetColor( it->color.GetX(), it->color.GetY(), it->color.GetZ(), it->alpha  );

        Vector2f position( it->position - cam->GetPosition() );
        r->FillCircle( it->size, position.x, position.y );
    }
}

/** Calculate Jitter Factor */
void Emitter::CalculateJitter( Particle &p, Vector2f &vel )
{
    //Vector2f forward, right;
    //forward.Set( 1, 1 );
    //right.Set( 1, -1 );

    //float r = random() * PI * 2.0f;
    //float u = sin(r) * crandom() * Jitter * 16.0f;
    //r = cos(r) * crandom() * Jitter * 16.0f;

    //Vector2f end, dir;//, delta;

    //end = (forward * 8102.0f * 16.0f) + p.position;
    //end = (right * r) + end;
    //dir = p.position - end;
    //dir.Normalize();

    //float scale = 555 + crandom() * 1800.0f;
    //delta = p.position * scale;

    //p.velocity.Set( dir );

    float angle = PI + (NextRand() * WanderRadius) * Jitter * 0.23434f - (0.23434f/2.0f);
    float speed = (1/NextRand()) / (10.0f);//*p.size);
    
    p.velocity.x = sin( crandom() ) * speed;//cos( random() / crandom() ) * speed;
    p.velocity.y = sin( crandom() ) * speed;


    //vel.Normalize();
    //Vector2f wander; 
    //wander.Set( (NextRand()-1.0f)*Jitter, (NextRand()-1.0f)*Jitter ); // jitter 
    //wander.Normalize();
    //wander = wander * ( WanderRadius ); // wander radius 
    //Vector2f work = vel;
    //work.Normalize();
    //work = work * ( WanderDistance ); // wander distance 
    //work = work + wander;
    //work.Normalize();
    //work = work * ( vel.Length() );
    //p.velocity = work;

}

/** Spawn a particle */
void Emitter::Spawn()
{

    Particle p;
    p.color    = StartColor;

    CalculateJitter( p, InitVel );
    p.fadeTime = AlphaFadeTime;
    p.position = Position;
    // p.velocity = InitVel;
    p.lifeTime = TIME + LifeSpan;

    p.acceleration = Acceleration;
    p.alpha = StartAlpha;
    p.size = ParticleSize;

    m_particlesCreated++;
    m_particles.push_back( p );

}

/** Clear dead particles */
void Emitter::ClearDead()
{
    type_Particles::iterator it = m_particles.begin();
    for(; it!=m_particles.end(); )
    {
        if ( it->isDead ) {
            it = m_particles.erase( it );
            m_spawnTimer = 0;
        } else { ++it; }
    }

}

/** Reset all Vars */
void Emitter::Reset()
{
    /* Spawn Rate */
    SpawnRate =  0.0f;
    /* Emition Angle Span */
    MaxAngle = 0.0f;
    /* Max Particles */
    MaxParticles = 0.0f;
    MaxTotalParticles = 0.0f;
    /** Life Span */
    LifeSpan = 0.0f;
    /** Life span of emitter */
    LifeSpanOfEmitter = 0.0f;
    /* Start Color */
    StartColor.ZeroOut();
    /* End Color */
    EndColor.ZeroOut();
    /* Color fade time */
    ColorFadeTime = 0.0f;
    StartAlpha = EndAlpha = 0.0f;
    /* Alpha Fade Time */
    AlphaFadeTime = 0.0f;
    ParticleSize = 0.0f;
    /** Jitter Factor */
    Jitter = 0.0f;
    /** Wander Radius */
    WanderRadius = 0.0f;
    /** Wander Distance */
    WanderDistance = 0.0f;

    /* Initial Velocity */
    InitVel.ZeroOut();
    /** Position of the emitter */
    Position.ZeroOut();
    /** Accel */
    Acceleration.ZeroOut();
    Friction = 1.0f;

    // spawn timer
    m_spawnTimer = 0.0f;
    m_particlesCreated = 0;

}